/*
 * Player.cpp
 *
 */

#include "Player.h"

#include <gl/gl.h>
#include <cmath>
#include <iostream>


Player::Player(Level *level, Skybox *skybox, int n)
{
	this->level = level;
	this->skybox = skybox;
	number = n;

	moveSpeed = MOVE_SPEED;
	rotSpeed = ROT_SPEED;
	// prepare bombs
	for(int i=0; i<NUM_BOMBS; i++)
		bomb[i] = new Bomb(level);
	texture = new GLuint;
	diameter = 0.15;

	bonus_bombs = 1;
	bonus_flame = 1;
	bonus_drunk = false;
	drunk_countdown = 0;
	bonus_skates = false;
	skates_countdown = 0;

	anim_t = 0.0f;
	anim_dt = ANIM_SPEED;

	lives = 3;
	blocked = false;
	timeout = 0;
	dead_rot = 0.0f;
	game_over = false;

	if (number == 0) {
		setPosition(1.5f, 1.51f, 0.0f);
		setRotation(-60.0f, 0.0f, 0.0f);
	}
	else if (number == 1) {
		setPosition(level->cols - 1.5f, level->rows - 1.51f, 0.0f);
		setRotation(-60.0f, 0.0f, 180.0f);
	}
}

Player::~Player() {
	for(int i=0; i<NUM_BOMBS; i++)
		delete bomb[i];

	for(int i=0; i<6; i++){
		//delete objBomb[i];
	}

//	delete lleg;
//	delete rleg;
//	delete larm;
//	delete rarm;
//	delete body;

}

void Player::setCameraMatrix()
{
	/* Distance from player */
	//glTranslatef(0,0, -10.0f);
	glTranslatef(0,0, -8.0f);
	glRotatef(r_X, 1.0f, 0.0f, 0.0f);
	/* Camera above the player */
	glTranslatef(0,0, -1.0f);
	//hero->renderGL();
	renderPlayer();
	glRotatef(-r_Z, 0.0f, 0.0f, 1.5f);
	glTranslatef(-p_X,-p_Y,-p_Z);
}

void Player::movePlayer(float x, float y, float z, float milis)
{
	// update bombs
	for(int i=0; i<NUM_BOMBS; i++){
		if(bomb[i]->isActive())
			bomb[i]->update(milis);
	}

	if (blocked) {
		timeout += milis;
		if (dead_rot < 90.0f) {
			dead_rot += milis*0.5f;
		}

		if (game_over)
			return;

		if (timeout > 3000.0f) {
			blocked = false;
			timeout = 0.0f;
			dead_rot = 0.0f;

			if (number == 0) {
				setPosition(1.5f, 1.51f, 0.0f);
				setRotation(-60.0f, 0.0f, 0.0f);
			}
			else if (number == 1) {
				setPosition(level->cols - 1.5f, level->rows - 1.51f, 0.0f);
				setRotation(-60.0f, 0.0f, 180.0f);
			}
		}
		return;
	}

	if (game_over)
		return;

	if (level->model[int(p_X)][int(p_Y)].isOnFire) {
		blocked = true;
		lives--;
		level->model[int(p_X)][int(p_Y)].removeModel3dPointer((Model3D*)this);
		if(bonus_bombs!=1)
			bonus_bombs = bonus_bombs/2;
		if(bonus_flame!=1)
			bonus_flame = bonus_flame/2;
		bonus_drunk = false;
		this->takeAwaySkates();
		return;
	}

	/* Animation */
	if ((y < 0.5f) && (y > -0.5f) && (x < 0.5f) && (x > -0.5f)) {
		if (anim_t > 0.01f) {
			anim_t = anim_t - ANIM_SPEED*milis;
		}
		if (anim_t < -0.01f) {
			anim_t = anim_t + ANIM_SPEED*milis;
		}
	}
	if ((y > 0.5f) || (x > 0.5f)) {
		anim_t = anim_t + anim_dt*milis;
		if ((anim_t > HALF_PI) || (anim_t < -HALF_PI)) {
			anim_dt = -anim_dt;
			anim_t = anim_t + anim_dt*milis;
		}
	}
	else if ((y < -0.5f) || (x < -0.5f)) {
		anim_t = anim_t - anim_dt*milis;
		if ((anim_t > HALF_PI) || (anim_t < -HALF_PI)) {
			anim_dt = -anim_dt;
			anim_t = anim_t - anim_dt*milis;
		}
	}

	/* Account for different frame rates */
	x = x*milis;
	y = y*milis;
	z = z*milis;

	/* Change position based on current view angle*/
	float dx = -sin(r_Z*PI_OVER_180)*moveSpeed*y + cos(r_Z*PI_OVER_180)*moveSpeed*x;
	float dy = cos(r_Z*PI_OVER_180)*moveSpeed*y + sin(r_Z*PI_OVER_180)*moveSpeed*x;

	Vertex p(p_X, p_Y, p_Z);
	Vertex d(p_X + dx, p_Y+dy, p_Z);

	level->model[int(p_X)][int(p_Y)].removeModel3dPointer((Model3D*)this);
	level->move(p,d,0.15f,0.0f);

	p_X = d.x;
	p_Y = d.y;
	p_Z = d.z;

	level->model[int(p_X)][int(p_Y)].addModel3dPointer((Model3D*)this);
}

void Player::rotatePlayer(float x, float z, float milis)
{
	x = x*milis;
	r_X = r_X + rotSpeed*x;

	if (!blocked) {
		z = z*milis;
		r_Z = r_Z + rotSpeed*z;
	}

	if (r_X < -70.f)
		r_X = -70.0f;
	if (r_X > 70.0f)
		r_X = 70.0f;

	skybox->setRotation((number == 0 ? true : false), r_X, -r_Z);
}

bool Player::isBlocked() {
	return blocked;
}

bool Player::isDead() {
	if (lives <= 0)
		return true;
	else
		return false;
}


int Player::numFlame() {
	return bonus_flame;
}

int Player::numBombs() {
	return bonus_bombs;
}

int Player::numLives() {
	return lives;
}

void Player::initializeGL(){
	//hero = new ObjModel("data/weird.obj");
	//hero = new ObjModel("data/bomberman.obj");
	if (number == 0) {
		body = new ObjModel("data/player_body0.obj");
		lleg = new ObjModel("data/player_lleg0.obj");
		rleg = new ObjModel("data/player_rleg0.obj");
		larm = new ObjModel("data/player_larm0.obj");
		rarm = new ObjModel("data/player_rarm0.obj");
	}
	else if (number == 1) {
		body = new ObjModel("data/player_body1.obj");
		lleg = new ObjModel("data/player_lleg1.obj");
		rleg = new ObjModel("data/player_rleg1.obj");
		larm = new ObjModel("data/player_larm1.obj");
		rarm = new ObjModel("data/player_rarm1.obj");

	}
	// initialize all (6) bomb 3D models
	for(int i=0; i<6; i++){
		char str[50];
		sprintf(str, "data/bomb%d.obj", (i+1));
		objBomb[i] = new ObjModel(str);
	}
	// initialize explosion texture
	Model3D::buildTexture("data/particle3.bmp", *texture);
	// initialize bombs
	for(int i=0; i<NUM_BOMBS; i++){
		bomb[i]->initializeGL(objBomb, texture);
	}
}

void Player::renderPlayer() {
	glPushMatrix();

	glTranslatef(0.0f, 0.0f, -cos(anim_t)*0.07f + 0.07f);
	glTranslatef(0.0f, 0.0f, dead_rot/(90.0f*5));
	glRotatef(dead_rot,1.0f,0.0f,0.0f);

	body->renderGL();

	glPushMatrix();
	glTranslatef(-0.05f, 0, 0.30f);
	glRotatef(sin(anim_t)*35.0f, 1.0f, 0.0f, 0.0f);
	lleg->renderGL();
	glPopMatrix();

	glPushMatrix();
	glTranslatef(0.05f, 0, 0.30f);
	glRotatef(-sin(anim_t)*35.0f, 1.0f, 0.0f, 0.0f);
	rleg->renderGL();
	glPopMatrix();

	glPushMatrix();
	glTranslatef(-0.1f, 0, 0.50f);
	glRotatef(-sin(anim_t)*35.0f, 1.0f, 0.0f, 0.0f);
	larm->renderGL();
	glPopMatrix();

	glPushMatrix();
	glTranslatef(0.1f, 0, 0.50f);
	glRotatef(sin(anim_t)*35.0f, 1.0f, 0.0f, 0.0f);
	rarm->renderGL();
	glPopMatrix();

	glPopMatrix();
}

void Player::renderGL()
{
	glPushMatrix();
	glTranslatef(p_X, p_Y, p_Z);
	glRotatef(r_Y, 0.0f, 1.0f, 0.0f);
	glRotatef(r_Z, 0.0f, 0.0f, 1.0f);
	renderPlayer();
	glPopMatrix();
}

bool Player::setBomb(){

	if (blocked || game_over)
		return false;

	// check if there is already a bomb on this position
	for(int i=0; i<NUM_BOMBS && i<bonus_bombs; i++){
		if(bomb[i]->isActive()){
			Vertex v = bomb[i]->getPosition();
			if((int)p_X == (int)v.x && (int)p_Y == (int)v.y)
				return false;
		}
	}
	// else set a bomb
	for(int i=0; i<NUM_BOMBS && i<bonus_bombs; i++){
		if(!(bomb[i]->isActive())){
			bomb[i]->activate((int)p_X, (int)p_Y, bonus_flame);
			return true;
		}
	}
	return false;
}

void Player::renderBombs(){
	// draw bombs
	for(int i=0; i<NUM_BOMBS; i++){
		if(bomb[i]->isActive())
			bomb[i]->renderGL();
	}
}


/*take necessary action on picking up bonus*/
void Player::pickupBonus(int bonus_id){
	switch(bonus_id){
	case 1:
		if(bonus_bombs<8)
			bonus_bombs++;
		break;
	case 2:
		if(bonus_flame<8)
			bonus_flame++;
		break;
	case 3:
		bonus_drunk = true;
		drunk_countdown = 10000.0;
		break;
	case 4:
		bonus_skates = true;
		skates_countdown = 10000.0;
		moveSpeed *= 2;
		break;
	}
}


bool Player::isDrunk(){
	return bonus_drunk;
}

void Player::setSober(){
	bonus_drunk = false;
}

bool Player::isOnSkates(){
	return bonus_skates;
}

void Player::takeAwaySkates(){
	bonus_skates = false;
	moveSpeed = MOVE_SPEED;
}
